/**
 * ============================================================
 * Gmail自動管理台帳 GAS v2.0
 * itdoor 無償サンプル  https://www.itdoor.jp/
 * 改変・社内利用可／商用配布は要相談。お問い合わせ: https://www.itdoor.jp/contact/
 *
 * 動作: 5分間隔で Gmail 未読メールを Sheets 台帳に追記
 * v2 変更: 管理番号(連番)・本文全体保存・備考列・対応ステータス
 * 重複防止: Message-ID 方式（処理済IDシートで管理）
 * クォータ対策: newer_than:7m で境界スキップ回避、1日288回実行
 * ============================================================
 */

// === 設定 ===
const CONFIG = {
  SHEET_NAME:        '管理台帳',
  DEDUP_SHEET:       '処理済ID',       // Message-ID保存用シート（自動作成）
  LOG_SHEET:         '実行ログ',        // クォータ消費ログ（自動作成）
  QUERY:             'is:unread newer_than:7m',  // 5分間隔+2分マージン
  MAX_THREADS:       50,                // 1回の実行で処理する上限
  TRIGGER_MINUTES:   5,                 // トリガー間隔
  DEDUP_RETAIN_DAYS: 30,                // 重複IDの保持期間
  BODY_MAX_LENGTH:   2000,              // メール本文の保存上限文字数
};

/**
 * メインエントリ（時間トリガーから呼ばれる）
 */
function main() {
  const t0 = Date.now();
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const log = { processed: 0, skipped: 0, errors: 0 };

  try {
    const sheet     = getOrCreateSheet(ss, CONFIG.SHEET_NAME, getLedgerHeader());
    const dedupSet  = loadDedupSet(ss);
    const threads   = GmailApp.search(CONFIG.QUERY, 0, CONFIG.MAX_THREADS);

    let mgmtNo = getNextManagementNumber(sheet);
    const rows = [];
    const newIds = [];

    threads.forEach(thread => {
      thread.getMessages().forEach(msg => {
        try {
          if (!msg.isUnread()) { log.skipped++; return; }
          const msgId = msg.getId();
          if (dedupSet.has(msgId)) { log.skipped++; return; }

          const row = parseMessage(msg, mgmtNo);
          rows.push(row);
          newIds.push([msgId, new Date()]);
          msg.markRead();
          log.processed++;
          mgmtNo++;
        } catch (e) {
          log.errors++;
          console.error('parse error:', e);
        }
      });
    });

    if (rows.length > 0) {
      sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length).setValues(rows);
    }
    if (newIds.length > 0) {
      appendDedup(ss, newIds);
    }

    pruneDedup(ss);
    writeLog(ss, log, Date.now() - t0);
  } catch (e) {
    console.error('main error:', e);
    writeLog(ss, { processed: 0, skipped: 0, errors: 1, fatal: e.message }, Date.now() - t0);
  }
}

/**
 * 1メッセージをパースして1行配列に変換
 *  列順: 管理番号 / 受信日時 / 送信者 / 件名 / メール内容 / 担当者 / 優先度 / 対応期限 / 備考 / 対応ステータス / Gmailリンク
 */
function parseMessage(msg, mgmtNo) {
  let body = msg.getPlainBody() || '';
  if (body.length > CONFIG.BODY_MAX_LENGTH) {
    body = body.substring(0, CONFIG.BODY_MAX_LENGTH) + '\n...(以下省略)';
  }
  const receivedDate = msg.getDate();
  const subject = msg.getSubject() || '';
  const priority = detectPriority(subject);
  const dueDate = computeDueDate(receivedDate, priority);
  const gmailLink = msg.getThread().getPermalink();

  return [
    mgmtNo,           // 管理番号（連番）
    receivedDate,     // 受信日時
    msg.getFrom(),    // 送信者
    subject,          // 件名
    body,             // メール内容
    '',               // 担当者（手動）
    priority,         // 優先度（件名キーワード自動判定、手動上書き可）
    dueDate,          // 対応期限（受信日 + 優先度別日数、手動上書き可）
    '',               // 備考（手動）
    '未対応',         // 対応ステータス
    gmailLink,        // Gmailリンク（元メールへ直接ジャンプ）
  ];
}

function getLedgerHeader() {
  return ['管理番号', '受信日時', '送信者', '件名', 'メール内容',
          '担当者', '優先度', '対応期限', '備考', '対応ステータス', 'Gmailリンク'];
}

/**
 * 件名から優先度を自動判定（手動上書き可）
 * 至急/緊急/Urgent/ASAP を含む → 高、それ以外 → 中
 */
function detectPriority(subject) {
  if (/至急|緊急|urgent|ASAP/i.test(subject || '')) return '高';
  return '中';
}

/**
 * 受信日から対応期限を計算（優先度別SLA）
 *   高 = +1日 / 中 = +3日 / 低 = +7日
 */
function computeDueDate(receivedDate, priority) {
  const days = priority === '高' ? 1 : (priority === '低' ? 7 : 3);
  const d = new Date(receivedDate);
  d.setDate(d.getDate() + days);
  return d;
}

/**
 * 次の管理番号を採番（既存最大+1、空なら1）
 */
function getNextManagementNumber(sheet) {
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return 1;
  const numbers = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
  let maxN = 0;
  numbers.forEach(r => {
    const n = Number(r[0]);
    if (!isNaN(n) && n > maxN) maxN = n;
  });
  return maxN + 1;
}

/**
 * シート取得or作成（ヘッダ自動セット）
 */
function getOrCreateSheet(ss, name, headers) {
  let sheet = ss.getSheetByName(name);
  if (!sheet) {
    sheet = ss.insertSheet(name);
    if (headers) {
      sheet.getRange(1, 1, 1, headers.length).setValues([headers]).setFontWeight('bold');
      sheet.setFrozenRows(1);
    }
  }
  return sheet;
}

/**
 * 重複防止: Message-ID セット読込み
 */
function loadDedupSet(ss) {
  const sheet = getOrCreateSheet(ss, CONFIG.DEDUP_SHEET, ['Message-ID', '記録日時']);
  const lastRow = sheet.getLastRow();
  const set = new Set();
  if (lastRow >= 2) {
    const ids = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
    ids.forEach(r => { if (r[0]) set.add(String(r[0])); });
  }
  return set;
}

function appendDedup(ss, rows) {
  const sheet = ss.getSheetByName(CONFIG.DEDUP_SHEET);
  sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 2).setValues(rows);
}

/**
 * 重複防止シートの古いエントリを削除
 */
function pruneDedup(ss) {
  const sheet = ss.getSheetByName(CONFIG.DEDUP_SHEET);
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return;
  const cutoff = new Date(Date.now() - CONFIG.DEDUP_RETAIN_DAYS * 86400000);
  const data = sheet.getRange(2, 1, lastRow - 1, 2).getValues();
  const kept = data.filter(r => r[1] && new Date(r[1]) > cutoff);
  sheet.getRange(2, 1, lastRow - 1, 2).clearContent();
  if (kept.length > 0) {
    sheet.getRange(2, 1, kept.length, 2).setValues(kept);
  }
}

/**
 * 実行ログ（クォータ監視用）
 */
function writeLog(ss, log, elapsedMs) {
  const sheet = getOrCreateSheet(ss, CONFIG.LOG_SHEET,
    ['実行時刻', '処理数', 'スキップ', 'エラー', '所要ms', '備考']);
  sheet.appendRow([
    new Date(),
    log.processed,
    log.skipped,
    log.errors,
    elapsedMs,
    log.fatal || '',
  ]);
  const total = sheet.getLastRow();
  if (total > 1001) sheet.deleteRows(2, total - 1001);
}

/**
 * トリガー設置（初回手動実行）
 */
function installTrigger() {
  ScriptApp.getProjectTriggers().forEach(t => {
    if (t.getHandlerFunction() === 'main') ScriptApp.deleteTrigger(t);
  });
  ScriptApp.newTrigger('main')
    .timeBased()
    .everyMinutes(CONFIG.TRIGGER_MINUTES)
    .create();
  console.log('Trigger installed: every ' + CONFIG.TRIGGER_MINUTES + ' minutes');
}

/**
 * トリガー削除（停止）
 */
function uninstallTrigger() {
  ScriptApp.getProjectTriggers().forEach(t => {
    if (t.getHandlerFunction() === 'main') ScriptApp.deleteTrigger(t);
  });
  console.log('Trigger removed');
}

/**
 * 初期化（シート構造を一括作成、本番投入前に1度実行）
 */
function initializeSheets() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  getOrCreateSheet(ss, CONFIG.SHEET_NAME, getLedgerHeader());
  getOrCreateSheet(ss, CONFIG.DEDUP_SHEET, ['Message-ID', '記録日時']);
  getOrCreateSheet(ss, CONFIG.LOG_SHEET,
    ['実行時刻', '処理数', 'スキップ', 'エラー', '所要ms', '備考']);
  console.log('Sheets initialized');
}
